Add Stackdriver Trace V2 models#87
Add Stackdriver Trace V2 models#87liyanhui1228 merged 21 commits intocensus-instrumentation:masterfrom
Conversation
|
|
||
| def _format_attribute_value(value): | ||
| if type(value).__name__ == 'str': | ||
| value_type = 'string_value' |
There was a problem hiding this comment.
The string_value value is a TruncatableString which has a value field.
There was a problem hiding this comment.
Good catch! Done.
There was a problem hiding this comment.
For Python 2/3 compatibility, we could check for bytes, str, and unicode, and convert them to str using 'utf-8' encoding. Just doing str might be good enough for now, though.`
|
Yes will change the StackdriverExporter to use the models in later commits. |
…encensus-python into stackdriver-v2
| if type(value).__name__ == 'str': | ||
| value_type = 'string_value' | ||
| value = _get_truncatable_str(value) | ||
| elif type(value).__name__ == 'int': |
There was a problem hiding this comment.
Can just do if isinstance(value, int) I think. Same for bool and str
There was a problem hiding this comment.
isinstance(True, int) will also return True. Changed to put the check for bool at the first if statement and check int later.
|
|
||
| def _format_attribute_value(value): | ||
| if type(value).__name__ == 'str': | ||
| value_type = 'string_value' |
There was a problem hiding this comment.
For Python 2/3 compatibility, we could check for bytes, str, and unicode, and convert them to str using 'utf-8' encoding. Just doing str might be good enough for now, though.`
|
|
||
| :type attributes: dict | ||
| :param attributes: The set of attributes. Each attribute's key can be up | ||
| to 128 bytes long. The value can be a string up to 256 |
There was a problem hiding this comment.
Should we check and enforce these limits in the code?
There was a problem hiding this comment.
Added check for length of the attribute key. The length of string value is checked in opencensus.trace.utils._get_truncatable_str when converting to TruncatableString.
|
|
||
| self.attributes = attributes | ||
|
|
||
| def set_attribute(self, key, value): |
There was a problem hiding this comment.
Is there any need for a "delete attribute" in the API? I think probably no, but I wanted to mention it.
| if attributes is None: | ||
| attributes = {} | ||
|
|
||
| self.attributes = attributes |
There was a problem hiding this comment.
We should probably copy the attributes dictionary instead of taking it by reference, so that the caller can't accidentally change our internal dictionary. E.g. something like
self.attributes = dict(attributes or {})
This is not absolutely required, but it's a good pattern to follow in general, and especially in constructors, to avoid two pieces of code sharing a list or dict without realizing it.
There was a problem hiding this comment.
Good catch! Done.
| value = self.attributes.get(key) | ||
| value_json = _format_attribute_value(value) | ||
| attributes_json[key] = value_json | ||
|
|
There was a problem hiding this comment.
Not required, but it you like, you could also do this:
attributes_json = {key: _format_attribute_value(value)
for key, value in self.attributes}
| """ | ||
| :type trace: dict | ||
| :param trace: Trace collected. | ||
| :type spans: dict |
There was a problem hiding this comment.
Should this be a private method? Otherwise, we should probably explain the translation a bit in the comment.
|
|
||
| def add_time_event(self, time_event): | ||
| """Add a TimeEvent.""" | ||
| self.time_events.append(time_event) |
There was a problem hiding this comment.
We might want to check that this is a TimeEvent and throw TypeError otherwise. Same as link below.
|
You are going to have a massive merge conflict between this and the big rename. Which one are you going to do first? |
|
The Stackdriver V2 won't be included in the first release. So I'll merge the restructure PR first. |
| self.attributes = attributes | ||
|
|
||
| def format_link_json(self): | ||
| """Conver a Link object to json format.""" |
| count. | ||
| """ | ||
| str_bytes = str_to_convert.encode(UTF8) | ||
| str_len = len(str_bytes) |
There was a problem hiding this comment.
This seems kind of problematic, because you could convert a code point to a 2 or 3 byte utf-8 sequence, and then truncate the string in the middle of that sequence, creating an invalid string that causing an exception to be thrown.
But I think you can get around this by changing the code below to
truncated = str_bytes.decode(UTF8, errors='ignore')
This seemed to do the right thing in both Python 2 and 3. Can you add a unit test where you call this on a string with 127 ascii characters followed by a some non-ascii characters?
I used the following code to play with truncation: ('\u2603\u2603'.encode('utf-8')[0:5]).decode('utf-8', errors='ignore').
There was a problem hiding this comment.
Thanks for the explanation! Added the unit test for that.
| if str_len > limit: | ||
| str_bytes = str_bytes[:limit] | ||
|
|
||
| result = str_bytes.decode(UTF8) |
There was a problem hiding this comment.
Same comment here as above. Perhaps one of these functions could call the other, or have a helper function that takes a (string, limit) and returns (truncated_string, truncated_byte_count)?
There was a problem hiding this comment.
Good suggestion, done.
…encensus-python into stackdriver-v2
…census-python into stackdriver-v2
duggelz
left a comment
There was a problem hiding this comment.
LGTM except I'm curious about the randint change
| than 0 and unique within a trace. | ||
| """ | ||
| span_id = random.getrandbits(64) | ||
| span_id = random.randint(10**15, 10**16 - 1) |
There was a problem hiding this comment.
Because the V2 API only accepts 16-digit span_id, but we can also trim the span_id in the stackdriver_exporter.
There was a problem hiding this comment.
Ok. Maybe document that rationale, and/or make those named constants.
| :returns: The string it self if not exceeded length, or truncated string | ||
| if exceeded and the truncated byte count. | ||
| """ | ||
| if limit is None: |
There was a problem hiding this comment.
Could also just do limit=MAX_LENGTH above in the function signature.
For #78